//-
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    this work for additional information regarding copyright ownership.
    The ASF licenses this file to You under the Apache License, Version 2.0
    (the "License"); you may not use this file except in compliance with
    the License.  You may obtain a copy of the License at

         http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

include /app/helpers/jade/mixins

mixin form-field__sensitive({ label, modelFilter, modelSensitive, name, placeholder })
    .form-field.form-field__sensitive.ignite-form-field
        +form-field__label({ label, name })
            +form-field__tooltip({ title: 'You can set case sensitive search' })
        .form-field__control.form-field__control-group
            +form-field__input({ name, model: modelFilter, placeholder })(
                type='text'
            )
            label.btn-ignite.btn-ignite--secondary
                +form-field__input({ name: `${ name } + "Sensitive"`, model: modelSensitive, placeholder })(
                    type='checkbox'
                )
                span Cs
        .form-field__errors(
            ng-messages=`$input.$error`
            ng-show=`($input.$dirty || $input.$touched || $input.$submitted) && $input.$invalid`
        )

mixin btn-toolbar(btn, click, tip, focusId)
    i.btn.btn-default.fa(class=btn ng-click=click bs-tooltip='' data-title=tip ignite-on-click-focus=focusId data-trigger='hover' data-placement='bottom')

mixin btn-toolbar-data(btn, kind, tip)
    i.btn.btn-default.fa(class=btn ng-click=`setResult(paragraph, '${kind}')` ng-class=`{active: resultEq(paragraph, '${kind}')}` bs-tooltip='' data-title=tip data-trigger='hover' data-placement='bottom')

mixin result-toolbar
    .btn-group(ng-model='paragraph.result' ng-click='$event.stopPropagation()' style='left: 50%; margin: 0 0 0 -70px;display: block;')
        +btn-toolbar-data('fa-table', 'table', 'Show data in tabular form')
        +btn-toolbar-data('fa-bar-chart', 'bar', 'Show bar chart<br/>By default first column - X values, second column - Y values<br/>In case of one column it will be treated as Y values')
        +btn-toolbar-data('fa-pie-chart', 'pie', 'Show pie chart<br/>By default first column - pie labels, second column - pie values<br/>In case of one column it will be treated as pie values')
        +btn-toolbar-data('fa-line-chart', 'line', 'Show line chart<br/>By default first column - X values, second column - Y values<br/>In case of one column it will be treated as Y values')
        +btn-toolbar-data('fa-area-chart', 'area', 'Show area chart<br/>By default first column - X values, second column - Y values<br/>In case of one column it will be treated as Y values')

mixin chart-settings
    .total.row
        .col-xs-7
            .chart-settings-link(ng-show='paragraph.chart && paragraph.chartColumns.length > 0')
                a(title='Click to show chart settings dialog' ng-click='$event.stopPropagation()' bs-popover data-template-url='{{ $ctrl.chartSettingsTemplateUrl }}' data-placement='bottom' data-auto-close='1' data-trigger='click')
                    i.fa.fa-bars
                    | Chart settings
                div(ng-show='paragraphTimeSpanVisible(paragraph)')
                    label Show
                    button.select-manual-caret.btn.btn-default(ng-model='paragraph.timeLineSpan' ng-change='applyChartSettings(paragraph)' bs-options='item for item in timeLineSpans' bs-select data-caret-html='<span class="caret"></span>')
                    label min

                div
                    label Duration: #[b {{paragraph.duration | duration}}]
                    label.margin-left-dflt(ng-show='paragraph.localQueryMode') NodeID8: #[b {{paragraph.resNodeId | id8}}]
        .col-xs-2
            +result-toolbar

mixin query-settings
    div
        .form-field--inline(
            bs-tooltip
            data-placement='top'
            data-title='Max number of rows to show in query result as one page'
        )
            +form-field__dropdown({
                label: 'Rows per page:',
                model: 'paragraph.pageSize',
                name: '"pageSize" + paragraph.id',
                options: 'pageSizesOptions'
            })

        .form-field--inline(
            bs-tooltip
            data-placement='top'
            data-title='Limit query max results to specified number of pages'
        )
            +form-field__dropdown({
                label: 'Max pages:',
                model: 'paragraph.maxPages',
                name: '"maxPages" + paragraph.id',
                options: 'maxPages'
            })

        .form-field--inline(
            bs-tooltip
            data-placement='bottom'
            data-title='Configure periodical execution of last successfully executed query'
        )
            button.btn-ignite-group(
                bs-popover
                data-template-url='{{ $ctrl.paragraphRateTemplateUrl }}'
                data-placement='bottom-right'
                data-auto-close='1'
                data-trigger='click'
            )
                .btn-ignite(
                    ng-class='{\
                        "btn-ignite--primary": paragraph.rate && paragraph.rate.installed,\
                        "btn-ignite--secondary": !(paragraph.rate && paragraph.rate.installed),\
                    }'
                )
                    svg(ignite-icon='clock')
                    | &nbsp; {{ rateAsString(paragraph) }}
                .btn-ignite(
                    ng-class='{\
                        "btn-ignite--primary": paragraph.rate && paragraph.rate.installed,\
                        "btn-ignite--secondary": !(paragraph.rate && paragraph.rate.installed),\
                    }'
                )
                    span.icon.fa.fa-caret-down
    div
        .row(ng-if='nonCollocatedJoinsAvailable(paragraph)')
            +form-field__checkbox({
                label: 'Allow non-collocated joins',
                model: 'paragraph.nonCollocatedJoins',
                name: '"nonCollocatedJoins" + paragraph.id',
                tip: 'Non-collocated joins is a special mode that allow to join data across cluster without collocation.<br/>\
                Nested joins are not supported for now.<br/>\
                <b>NOTE</b>: In some cases it may consume more heap memory or may take a long time than collocated joins.',
                tipOpts: { placement: 'top' }
            })

        .row(ng-if='collocatedJoinsAvailable(paragraph)')
            +form-field__checkbox({
                label: 'Collocated Query',
                model: 'paragraph.collocated',
                name: '"collocated" + paragraph.id',
                tip: 'Used For Optimization Purposes Of Queries With GROUP BY Statements.<br/>\
                <b>NOTE:</b> Whenever Ignite executes a distributed query, it sends sub-queries to individual cluster members.<br/>\
                If you know in advance that the elements of your query selection are collocated together on the same node\
                and you group by collocated key (primary or affinity key), then Ignite can make significant performance and\
                network optimizations by grouping data on remote nodes.',
                tipOpts: { placement: 'top' }
            })

        .row(ng-if='enforceJoinOrderAvailable(paragraph)')
            +form-field__checkbox({
                label: 'Enforce join order',
                model: 'paragraph.enforceJoinOrder',
                name: '"enforceJoinOrder" + paragraph.id',
                tip: 'Enforce join order of tables in the query.<br/>\
                If <b>set</b>, then query optimizer will not reorder tables within join.<br/>\
                <b>NOTE:</b> It is not recommended to enable this property unless you have verified that\
                indexes are not selected in optimal order.',
                tipOpts: { placement: 'top' }
            })

        .row(ng-if='lazyQueryAvailable(paragraph)')
            +form-field__checkbox({
                label: 'Lazy result set',
                model: 'paragraph.lazy',
                name: '"lazy" + paragraph.id',
                tip: 'By default Ignite attempts to fetch the whole query result set to memory and send it to the client.<br/>\
                For small and medium result sets this provides optimal performance and minimize duration of internal database locks, thus increasing concurrency.<br/>\
                If result set is too big to fit in available memory this could lead to excessive GC pauses and even OutOfMemoryError.<br/>\
                Use this flag as a hint for Ignite to fetch result set lazily, thus minimizing memory consumption at the cost of moderate performance hit.',
                tipOpts: { placement: 'top' }
            })

mixin query-actions
    button.btn-ignite.btn-ignite--primary(ng-disabled='!queryAvailable(paragraph)' ng-click='execute(paragraph)')
        span.icon-left.fa.fa-fw.fa-play(ng-hide='paragraph.executionInProgress(false)')
        span.icon-left.fa.fa-fw.fa-refresh.fa-spin(ng-show='paragraph.executionInProgress(false)')
        | Execute

    button.btn-ignite.btn-ignite--primary(ng-disabled='!queryAvailable(paragraph)' ng-click='execute(paragraph, true)')
        span.icon-left.fa.fa-fw.fa-play(ng-hide='paragraph.executionInProgress(true)')
        span.icon-left.fa.fa-fw.fa-refresh.fa-spin(ng-show='paragraph.executionInProgress(true)')
        | Execute on selected node

    button.btn-ignite.btn-ignite--secondary(ng-disabled='!queryAvailable(paragraph)' ng-click='explain(paragraph)' data-placement='bottom' bs-tooltip='' data-title='{{queryTooltip(paragraph, "explain query")}}')
        | Explain

    button.btn-ignite.btn-ignite--secondary(ng-if='paragraph.executionInProgress(false) || paragraph.executionInProgress(true)' ng-click='cancelQuery(paragraph)' data-placement='bottom' bs-tooltip='' data-title='{{"Cancel query execution"}}')
        | Cancel

mixin table-result-heading-query
    .total.row
        .col-xs-7
            grid-column-selector(grid-api='paragraph.gridOptions.api')
                .fa.fa-bars.icon
            label Page: #[b {{paragraph.page}}]
            label.margin-left-dflt Results so far: #[b {{paragraph.rows.length + paragraph.total}}]
            label.margin-left-dflt Duration: #[b {{paragraph.duration | duration}}]
            label.margin-left-dflt(ng-show='paragraph.localQueryMode') NodeID8: #[b {{paragraph.resNodeId | id8}}]
        .col-xs-2
            div(ng-if='paragraph.qryType === "query"')
                +result-toolbar
        .col-xs-3
            .pull-right
                .btn-ignite-group
                    button.btn-ignite.btn-ignite--primary(
                        ng-click='exportCsv(paragraph)'
                        ng-disabled='paragraph.loading'
                        bs-tooltip=''
                        ng-attr-title='{{ queryTooltip(paragraph, "export query results") }}'
                        data-trigger='hover'
                        data-placement='bottom'
                    )
                        svg(ignite-icon='csv' ng-if='!paragraph.csvIsPreparing')
                        svg.fa-spin(ignite-icon='refresh' ng-if='paragraph.csvIsPreparing')
                        |  &nbsp; Export

                    -var options = [{ text: 'Export', click: 'exportCsv(paragraph)' }, { text: 'Export all', click: 'exportCsvAll(paragraph)' }, { divider: true }, { text: '<span title="Copy current result page to clipboard">Copy to clipboard</span>', click: 'exportCsvToClipBoard(paragraph)' }]
                    button.btn-ignite.btn-ignite--primary(
                        ng-disabled='paragraph.loading'
                        bs-dropdown=`${JSON.stringify(options)}`
                        data-toggle='dropdown'
                        data-container='body'
                        data-placement='bottom-right'
                        data-html='true'
                    )
                        span.icon.fa.fa-caret-down


mixin table-result-heading-scan
    .total.row
        .col-xs-7
            grid-column-selector(grid-api='paragraph.gridOptions.api')
                .fa.fa-bars.icon
            label Page: #[b {{paragraph.page}}]
            label.margin-left-dflt Results so far: #[b {{paragraph.rows.length + paragraph.total}}]
            label.margin-left-dflt Duration: #[b {{paragraph.duration | duration}}]
            label.margin-left-dflt(ng-show='paragraph.localQueryMode') NodeID8: #[b {{paragraph.resNodeId | id8}}]
        .col-xs-2
            div(ng-if='paragraph.qryType === "query"')
                +result-toolbar
        .col-xs-3
            .pull-right
                .btn-group.panel-tip-container
                    // TODO: replace this logic for exporting under one component
                    button.btn.btn-primary.btn--with-icon(
                        ng-click='exportCsv(paragraph)'

                        ng-disabled='paragraph.loading || paragraph.csvIsPreparing'

                        bs-tooltip=''
                        ng-attr-title='{{ scanTooltip(paragraph) }}'

                        data-trigger='hover'
                        data-placement='bottom'
                    )
                        svg(ignite-icon='csv' ng-if='!paragraph.csvIsPreparing')
                        i.fa.fa-fw.fa-refresh.fa-spin(ng-if='paragraph.csvIsPreparing')
                        span Export

                    -var options = [{ text: "Export", click: 'exportCsv(paragraph)' }, { text: 'Export all', click: 'exportCsvAll(paragraph)' }, { divider: true }, { text: '<span title="Copy current result page to clipboard">Copy to clipboard</span>', click: 'exportCsvToClipBoard(paragraph)' }]
                    button.btn.dropdown-toggle.btn-primary(
                        ng-disabled='paragraph.loading || paragraph.csvIsPreparing'

                        bs-dropdown=`${JSON.stringify(options)}`

                        data-toggle='dropdown'
                        data-container='body'
                        data-placement='bottom-right'
                        data-html='true'
                    )
                        span.caret

mixin table-result-body
    .grid(ui-grid='paragraph.gridOptions' ui-grid-resize-columns ui-grid-exporter ui-grid-hovering)

mixin chart-result
    div(ng-hide='paragraph.scanExplain()')
        +chart-settings
        .empty(ng-show='paragraph.chartColumns.length > 0 && !paragraph.chartColumnsConfigured()') Cannot display chart. Please configure axis using #[b Chart settings]
        .empty(ng-show='paragraph.chartColumns.length == 0') Cannot display chart. Result set must contain Java build-in type columns. Please change query and execute it again.
        div(ng-show='paragraph.chartColumnsConfigured()')
            div(ng-show='paragraph.timeLineSupported() || !paragraph.chartTimeLineEnabled()')
                div(ng-repeat='chart in paragraph.charts')
                    nvd3(options='chart.options' data='chart.data' api='chart.api')
            .empty(ng-show='!paragraph.timeLineSupported() && paragraph.chartTimeLineEnabled()') Pie chart does not support 'TIME_LINE' column for X-axis. Please use another column for X-axis or switch to another chart.
    .empty(ng-show='paragraph.scanExplain()')
        .row
            .col-xs-4.col-xs-offset-4
                +result-toolbar
        label.margin-top-dflt Charts do not support #[b Explain] and #[b Scan] query

mixin paragraph-scan
    panel-title {{ paragraph.name }}
    panel-actions
        query-actions-button(actions='$ctrl.scanActions' item='paragraph')
    panel-content
        .col-sm-12.sql-controls
            .col-sm-3
                +form-field__dropdown({
                    label: 'Cache:',
                    model: 'paragraph.cacheName',
                    name: '"cache"',
                    placeholder: 'Choose cache',
                    options: 'caches'
                })
            .col-sm-3
                +form-field__sensitive({
                    label: 'Filter:',
                    modelFilter: 'paragraph.filter',
                    modelSensitive: 'paragraph.caseSensitive',
                    name: '"filter"',
                    placeholder: 'Enter filter'
                })

            .col-sm-3
                +form-field__dropdown({
                    label: 'Rows per page:',
                    model: 'paragraph.pageSize',
                    name: '"pageSize" + paragraph.id',
                    options: 'pageSizesOptions',
                    tip: 'Max number of rows to show in query result as one page',
                    tipOpts: { placement: 'top' }
                })

        .col-sm-12.sql-controls
            div
                button.btn-ignite.btn-ignite--primary(ng-disabled='!scanAvailable(paragraph)' ng-click='scan(paragraph)')
                    span.icon-left.fa.fa-fw.fa-play(ng-hide='paragraph.checkScanInProgress(false)')
                    span.icon-left.fa.fa-fw.fa-refresh.fa-spin(ng-show='paragraph.checkScanInProgress(false)')
                    | Scan

                button.btn-ignite.btn-ignite--primary(ng-disabled='!scanAvailable(paragraph)' ng-click='scan(paragraph, true)')
                    span.icon-left.fa.fa-fw.fa-play(ng-hide='paragraph.checkScanInProgress(true)')
                    span.icon-left.fa.fa-fw.fa-refresh.fa-spin(ng-show='paragraph.checkScanInProgress(true)')
                    | Scan on selected node

                button.btn-ignite.btn-ignite--secondary(ng-if='paragraph.checkScanInProgress(false) || paragraph.checkScanInProgress(true)' ng-click='cancelQuery(paragraph)' data-placement='bottom' bs-tooltip='' data-title='{{"Cancel query execution"}}')
                    | Cancel
            div

        .col-sm-12.sql-result(ng-if='paragraph.queryExecuted() && !paragraph.scanningInProgress' ng-switch='paragraph.resultType()')
            .error(ng-switch-when='error') Error: {{paragraph.error.message}}
            .empty(ng-switch-when='empty') Result set is empty. Duration: #[b {{paragraph.duration | duration}}]
            .table(ng-switch-when='table')
                +table-result-heading-scan
                +table-result-body
            .footer.clearfix()
                .pull-left
                    | Showing results for scan of #[b {{ paragraph.queryArgs.cacheName | defaultName }}]
                    span(ng-if='paragraph.queryArgs.filter') &nbsp; with filter: #[b {{ paragraph.queryArgs.filter }}]
                    span(ng-if='paragraph.queryArgs.localNid') &nbsp; on node: #[b {{ paragraph.queryArgs.localNid | limitTo:8 }}]

                -var nextVisibleCondition = 'paragraph.resultType() != "error" && !paragraph.loading && paragraph.queryId && paragraph.nonRefresh() && (paragraph.table() || paragraph.chart() && !paragraph.scanExplain())'

                .pull-right(ng-show=`${nextVisibleCondition}` ng-class='{disabled: paragraph.loading}' ng-click='!paragraph.loading && nextPage(paragraph)')
                    i.fa.fa-chevron-circle-right
                    a Next

mixin paragraph-query
    panel-title {{ paragraph.name }}
    panel-actions
        query-actions-button(actions='$ctrl.queryActions' item='paragraph')
    panel-content
        .col-sm-12
            .col-xs-8.col-sm-9(style='border-right: 1px solid #eee')
                .sql-editor(ignite-ace='{onLoad: aceInit(paragraph), theme: "chrome", mode: "sql", require: ["ace/ext/language_tools"],' +
                'advanced: {enableSnippets: false, enableBasicAutocompletion: true, enableLiveAutocompletion: true}}'
                ng-model='paragraph.query' on-selection-change='paragraph.partialQuery = $event')
            .col-xs-4.col-sm-3
                div(ng-show='caches.length > 0' style='padding: 5px 10px' st-table='displayedCaches' st-safe-src='caches')
                    lable.labelField.labelFormField Caches:
                    i.fa.fa-database.tipField(title='Click to show cache types metadata dialog' bs-popover data-template-url='{{ $ctrl.cacheMetadataTemplateUrl }}' data-placement='bottom-right' data-trigger='click' data-container='#{{ paragraph.id }}')
                    .input-tip
                        input.form-control(type='text' st-search='label' placeholder='Filter caches...')

                    .queries-notebook-displayed-caches
                        div(ng-repeat='cache in displayedCaches track by cache.value')
                            +form-field__radio({
                                label: '{{ cache.label }}',
                                model: 'paragraph.cacheName',
                                name: '"cache_" + [paragraph.id, $index].join("_")',
                                value: 'cache.value'
                            })

                    .settings-row
                        .row(ng-if='ddlAvailable(paragraph)')
                            +form-field__checkbox({
                                label: 'Use selected cache as default schema name',
                                model: 'paragraph.useAsDefaultSchema',
                                name: '"useAsDefaultSchema" + paragraph.id',
                                tip: 'Use selected cache as default schema name.<br/>\
                                    This will allow to execute query on specified cache without specify schema name.<br/>\
                                    <b>NOTE:</b> In future version of Ignite this feature will be removed.',
                                tipOpts: { placement: 'top' }
                            })
                .empty-caches(ng-show='displayedCaches.length == 0 && caches.length != 0')
                    no-data
                        label Wrong caches filter
                .empty-caches(ng-show='caches.length == 0')
                    no-data
                        label No caches
        .col-sm-12.sql-controls
            div
                +query-actions

            +query-settings
        .col-sm-12.sql-result(ng-if='paragraph.queryExecuted()' ng-switch='paragraph.resultType()')
            .error(ng-switch-when='error')
                label Error: {{paragraph.error.message}}
                br
                a(ng-show='paragraph.resultType() === "error"' ng-click='showStackTrace(paragraph)') Show more
            .empty(ng-switch-when='empty') Result set is empty. Duration: #[b {{paragraph.duration | duration}}]
            .table(ng-switch-when='table')
                +table-result-heading-query
                +table-result-body
            .chart(ng-switch-when='chart')
                +chart-result
            .footer.clearfix(ng-show='paragraph.resultType() !== "error"')
                a.pull-left(ng-click='showResultQuery(paragraph)') Show query

                -var nextVisibleCondition = 'paragraph.resultType() !== "error" && !paragraph.loading && paragraph.queryId && paragraph.nonRefresh() && (paragraph.table() || paragraph.chart() && !paragraph.scanExplain())'

                .pull-right(ng-show=`${nextVisibleCondition}` ng-class='{disabled: paragraph.loading}' ng-click='!paragraph.loading && nextPage(paragraph)')
                    i.fa.fa-chevron-circle-right
                    a Next

div(ng-if='notebook')
    .notebooks-top
        h1(ng-hide='notebook.edit')
            label {{notebook.name}}
            .btn-group(ng-if='!demo')
                +btn-toolbar('fa-pencil', 'notebook.edit = true;notebook.editName = notebook.name', 'Rename notebook')

        h1(ng-show='notebook.edit')
            input.form-control(ng-model='notebook.editName' required ignite-on-enter='renameNotebook(notebook.editName)' ignite-on-escape='notebook.edit = false;')
            i.btn.fa.fa-floppy-o(ng-show='notebook.editName' ng-click='renameNotebook(notebook.editName)' bs-tooltip data-title='Save notebook name' data-trigger='hover')

        cluster-selector

        .notebook-top-buttons
            a.dropdown-toggle(style='margin-right: 20px' data-toggle='dropdown' bs-dropdown='scrollParagraphs' data-placement='bottom-left') Scroll to query
                span.caret
            button.btn-ignite.btn-ignite--primary(ng-click='addQuery()' ignite-on-click-focus=focusId)
                svg.icon-left(ignite-icon='plus')
                | Add query

            button.btn-ignite.btn-ignite--primary(ng-click='addScan()' ignite-on-click-focus=focusId)
                svg.icon-left(ignite-icon='plus')
                | Add scan

div
    breadcrumbs
        a.link-success(ui-sref='base.sql.tabs') Notebooks
        span(ui-sref='.' ui-sref-active) Notebook '{{notebook.name}}'

    -var example = `CREATE TABLE Person(ID INTEGER PRIMARY KEY, NAME VARCHAR(100));\nINSERT INTO Person(ID, NAME) VALUES (1, 'Ed'), (2, 'Ann'), (3, 'Emma');\nSELECT * FROM Person;`;

    ignite-information(
        data-title='With query notebook you can'
        style='margin-bottom: 30px'
        ng-init=`example = "${example}"`
    )
        ul
            li Create any number of queries
            li Execute and explain SQL queries
            li Execute scan queries
            li View data in tabular form and as charts
            li
                a(href='https://apacheignite-sql.readme.io/docs/sql-reference-overview' target='_blank') More info
        .example
            .group
                .group-legend
                    label Examples:
                .group-content
                    .sql-editor(ignite-ace='{\
                        onLoad: aceInit({}),\
                        theme: "chrome",\
                        mode: "sql",\
                        require: ["ace/ext/language_tools"],\
                        showGutter: false,\
                        advanced: {\
                           enableSnippets: false,\
                           enableBasicAutocompletion: true,\
                           enableLiveAutocompletion: true\
                        }}'
                        ng-model='example'
                        readonly='true'
                    )

    .notebook-failed--block(ng-if='notebookLoadFailed')
        no-data
            h2 Failed to load notebook
            label.col-sm-12 Notebook not accessible any more. Go back to notebooks list.

    div(ng-if='notebook' ignite-loading='sqlLoading' ignite-loading-text='{{ loadingText }}' ignite-loading-position='top')
        .docs-body.paragraphs
            .panel-group
                .panel-paragraph(ng-repeat='paragraph in notebook.paragraphs' id='{{paragraph.id}}' ng-form='form_{{paragraph.id}}')
                    panel-collapsible(
                        ng-if='paragraph.qryType === "scan"'
                        opened='$ctrl.isParagraphOpened($index)'
                        on-close='$ctrl.onParagraphClose($index)'
                        on-open='$ctrl.onParagraphOpen($index)'
                    )
                        +paragraph-scan
                    panel-collapsible(
                        ng-if='paragraph.qryType === "query"'
                        opened='$ctrl.isParagraphOpened($index)'
                        on-close='$ctrl.onParagraphClose($index)'
                        on-open='$ctrl.onParagraphOpen($index)'
                    )
                        +paragraph-query
